package cn.xingzhe.monster.user.domain.model;

import cn.xingzhe.monster.user.domain.enums.UserStatusEnum;
import cn.xingzhe.monster.user.domain.exception.InvalidPasswordException;
import cn.xingzhe.monster.user.domain.exception.UserException;
import cn.xingzhe.monster.user.domain.service.PasswordHasher;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 用户领域模型
 * 包含用户相关的业务逻辑和业务规则
 *
 * @author System
 * @version 1.0.0
 * @since 2024-01-01
 */
@Getter
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class UserModel {

    /**
     * 用户ID
     */
    private String id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码（加密后的hash）
     */
    private String password;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 手机号
     */
    private String phone;

    /**
     * 用户状态
     */
    private UserStatusEnum status;

    /**
     * 角色ID列表
     */
    @Builder.Default
    private List<String> roleIds = new ArrayList<>();

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

    /**
     * 注册用户（通过邮箱）
     *
     * @param email    邮箱
     * @param password 密码（明文）
     * @param hasher   密码哈希服务
     * @return 用户领域模型
     */
    public static UserModel registerByEmail(String email, String password, PasswordHasher hasher) {
        validatePassword(password);
        LocalDateTime now = LocalDateTime.now();
        return UserModel.builder()
                .id(UUID.randomUUID().toString())
                .email(email)
                .username(email) // 默认使用邮箱作为用户名
                .password(hasher.encode(password))
                .status(UserStatusEnum.ACTIVE)
                .roleIds(new ArrayList<>())
                .createTime(now)
                .updateTime(now)
                .build();
    }

    /**
     * 注册用户（通过手机号）
     *
     * @param phone    手机号
     * @param password 密码（明文）
     * @param hasher   密码哈希服务
     * @return 用户领域模型
     */
    public static UserModel registerByPhone(String phone, String password, PasswordHasher hasher) {
        validatePassword(password);
        LocalDateTime now = LocalDateTime.now();
        return UserModel.builder()
                .id(UUID.randomUUID().toString())
                .phone(phone)
                .username(phone) // 默认使用手机号作为用户名
                .password(hasher.encode(password))
                .status(UserStatusEnum.ACTIVE)
                .roleIds(new ArrayList<>())
                .createTime(now)
                .updateTime(now)
                .build();
    }

    /**
     * 激活用户
     *
     * @return 新的用户模型（激活后）
     */
    public UserModel activate() {
        if (this.status == UserStatusEnum.ACTIVE) {
            return this;
        }
        return this.toBuilder()
                .status(UserStatusEnum.ACTIVE)
                .updateTime(LocalDateTime.now())
                .build();
    }

    /**
     * 锁定用户
     *
     * @return 新的用户模型（锁定后）
     */
    public UserModel lock() {
        if (this.status == UserStatusEnum.LOCKED) {
            return this;
        }
        return this.toBuilder()
                .status(UserStatusEnum.LOCKED)
                .updateTime(LocalDateTime.now())
                .build();
    }

    /**
     * 修改密码
     *
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @param hasher      密码哈希服务
     * @return 新的用户模型
     */
    public UserModel changePassword(String oldPassword, String newPassword, PasswordHasher hasher) {
        // 验证旧密码
        if (!verifyPassword(oldPassword, hasher)) {
            throw InvalidPasswordException.of();
        }

        validatePassword(newPassword);

        return this.toBuilder()
                .password(hasher.encode(newPassword))
                .updateTime(LocalDateTime.now())
                .build();
    }

    /**
     * 验证密码
     *
     * @param rawPassword 原始密码
     * @param hasher      密码哈希服务
     * @return 是否匹配
     */
    public boolean verifyPassword(String rawPassword, PasswordHasher hasher) {
        return hasher.matches(rawPassword, this.password);
    }

    /**
     * 分配角色
     *
     * @param newRoleIds 新的角色ID列表
     * @return 新的用户模型
     */
    public UserModel assignRoles(List<String> newRoleIds) {
        List<String> updatedRoleIds = new ArrayList<>(this.roleIds);
        for (String roleId : newRoleIds) {
            if (!updatedRoleIds.contains(roleId)) {
                updatedRoleIds.add(roleId);
            }
        }
        return this.toBuilder()
                .roleIds(updatedRoleIds)
                .updateTime(LocalDateTime.now())
                .build();
    }

    /**
     * 移除角色
     *
     * @param roleIdsToRemove 要移除的角色ID列表
     * @return 新的用户模型
     */
    public UserModel removeRoles(List<String> roleIdsToRemove) {
        List<String> updatedRoleIds = new ArrayList<>(this.roleIds);
        updatedRoleIds.removeAll(roleIdsToRemove);
        return this.toBuilder()
                .roleIds(updatedRoleIds)
                .updateTime(LocalDateTime.now())
                .build();
    }

    /**
     * 判断是否可以登录
     *
     * @return 是否可以登录
     */
    public boolean canLogin() {
        return this.status == UserStatusEnum.ACTIVE;
    }

    /**
     * 判断是否可以激活
     *
     * @return 是否可以激活
     */
    public boolean canActivate() {
        return this.status != UserStatusEnum.ACTIVE;
    }

    /**
     * 判断是否可以锁定
     *
     * @return 是否可以锁定
     */
    public boolean canLock() {
        return this.status != UserStatusEnum.LOCKED;
    }

    /**
     * 验证密码强度
     *
     * @param password 密码
     */
    private static void validatePassword(String password) {
        if (password == null || password.trim().isEmpty()) {
            throw new UserException("A0120", "密码不能为空");
        }
        if (password.length() < 6 || password.length() > 20) {
            throw new UserException("A0121", "密码长度必须在6-20位之间");
        }
    }


}

